package com.masonluo.mlonlinejudge.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.masonluo.mlonlinejudge.dao.ProblemTagRepository;
import com.masonluo.mlonlinejudge.dao.SelectProblemRepository;
import com.masonluo.mlonlinejudge.dao.TagRepository;
import com.masonluo.mlonlinejudge.entity.*;
import com.masonluo.mlonlinejudge.exceptions.ResourceExistException;
import com.masonluo.mlonlinejudge.exceptions.ResourceNotFoundException;
import com.masonluo.mlonlinejudge.mapper.SelectProblemMapper;
import com.masonluo.mlonlinejudge.mapper.TagMapper;
import com.masonluo.mlonlinejudge.model.bo.SelectProblemBo;
import com.masonluo.mlonlinejudge.model.dto.SelectProblemUploadDto;
import com.masonluo.mlonlinejudge.model.param.SelectProblemParam;
import com.masonluo.mlonlinejudge.model.vo.TagVo;
import com.masonluo.mlonlinejudge.service.RoleService;
import com.masonluo.mlonlinejudge.service.SelectProblemService;
import com.masonluo.mlonlinejudge.service.TagService;
import com.masonluo.mlonlinejudge.utils.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class SelectProblemServiceImpl implements SelectProblemService {

    private final SelectProblemRepository selectProblemRepository;

    private final ProblemTagRepository problemTagRepository;

    private final TagMapper tagMapper;

    private final TagRepository tagRepository;

    private final TagService tagService;

    private final SelectProblemMapper selectProblemMapper;

    private final RoleService roleService;

    public SelectProblemServiceImpl(SelectProblemRepository selectProblemRepository, ProblemTagRepository problemTagRepository, TagMapper tagMapper, TagRepository tagRepository, TagService tagService, SelectProblemMapper selectProblemMapper, RoleService roleService) {
        this.selectProblemRepository = selectProblemRepository;
        this.problemTagRepository = problemTagRepository;
        this.tagMapper = tagMapper;
        this.tagRepository = tagRepository;
        this.tagService = tagService;
        this.selectProblemMapper = selectProblemMapper;
        this.roleService = roleService;
    }

    @Override
    public int countAll() {
        return selectProblemRepository.countAll();
    }

    @Override
    public int countByIndexId(Integer indexId) {
        return selectProblemRepository.countByIndexId(indexId);
    }

    @Override
    public int countByUserId(Integer userId) {
        return selectProblemRepository.countByUserId(userId);
    }

    @Override
    public Integer countByAll(String tag, String title, Integer type) {
        return selectProblemRepository.countByAll(tag,title,type);
    }

    @Override
    public SelectProblemParam updateSelectProblemById(SelectProblemUploadDto selectProblemUploadDto, Integer userId) {
        SelectProblem bo = selectProblemRepository.selectById(selectProblemUploadDto.getId());
        if (bo != null){
            if (!Objects.equals(bo.getUserId(), userId)){
                String role = roleService.findByUserId(userId).getName();
                if (!"superAdmin".equals(role)){
                    throw new ResourceExistException(String.format("您不是超级管理员或该题目的创建者，无权修改题目"));
                }
            }
            SelectProblem selectProblem = selectProblemMapper.uploadDtoToDo(selectProblemUploadDto);
            List<TagVo> tags = selectProblemUploadDto.getTags();
            problemTagRepository.deleteByProblemId(bo.getId(), bo.getType());
            doProblemRelatedTag(tags,selectProblem);
            selectProblem.setUserId(bo.getUserId());
            selectProblem.setType(bo.getType());
            selectProblemRepository.updateById(selectProblem);
            return getSelectProblemById(selectProblemUploadDto.getId());

        }
        throw new ResourceNotFoundException("更新题目失败，请确认当前题目是否存在");
    }




    @Override
    public SelectProblemParam getSelectProblemById(Integer id) {
        SelectProblem selectProblem = selectProblemRepository.selectById(id);
        SelectProblemBo bo = selectProblemMapper.to(selectProblem);
        SelectProblemParam selectProblemParam = new SelectProblemParam(
                bo.getId(),
                bo.getType(),
                bo.getTitle(),
                bo.getAnswer(),
                bo.getCorrect(),
                bo.getLevel(),
                tagMapper.doToVo(problemTagRepository.findTagBySelectProblemId(id)),
                bo.getUserId(),
                bo.getIndexId()
        );
        //selectProblemParam.setTags(problemTagRepository.findTagBySelectProblemId(id));
        return selectProblemParam;
    }

    @Override
    public List<SelectProblemParam> getSelectProblemListByIndexId(Integer indexId, Integer pageNum, Integer pageSize) {
        IPage<SelectProblem> page = new Page<>(pageNum, pageSize);
        QueryWrapper<SelectProblem> wrapper = new QueryWrapper<>();
        wrapper.eq("index_id",indexId);
        IPage<SelectProblem> selectProblemIPage = selectProblemRepository.selectPage(page, wrapper);
        /*Map<String, Object> param = new HashMap<>();
        param.put("index_id",indexId);*/
        return sorter(selectProblemIPage,pageNum);

    }

    @Override
    public List<SelectProblemParam> getSelectProblemByPage(Integer pageNum, Integer pageSize) {
        IPage<SelectProblem> page = new Page<>(pageNum, pageSize);
        IPage<SelectProblem> selectProblemIPage = selectProblemRepository.selectPage(page, null);
        return sorter(selectProblemIPage,pageNum);

    }

    @Override
    public List<SelectProblemParam> getSelectProblem() {
        List<SelectProblem> selectProblem = selectProblemRepository.getSelectProblem();
        List<SelectProblemBo> bos = selectProblemMapper.to(selectProblem);
        List<SelectProblemParam> params = new ArrayList<>();
        for (SelectProblemBo bo:bos){
            SelectProblemParam selectProblemParam = new SelectProblemParam(
                    bo.getId(),
                    bo.getType(),
                    bo.getTitle(),
                    bo.getAnswer(),
                    bo.getCorrect(),
                    bo.getLevel(),
                    tagMapper.doToVo(problemTagRepository.findTagBySelectProblemId(bo.getId())),
                    bo.getUserId(),
                    bo.getIndexId()
            );
            params.add(selectProblemParam);
        }
        return params;
    }

    @Override
    public List<SelectProblemParam> getSelectProblemPageByUserId(Integer userId, Integer pageNum, Integer pageSize) {
        IPage<SelectProblem> page = new Page<>(pageNum, pageSize);
        QueryWrapper<SelectProblem> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId);
        IPage<SelectProblem> selectProblemIPage = selectProblemRepository.selectPage(page, wrapper);
        return sorter(selectProblemIPage,pageNum);
        // return selectProblemIPage.getRecords();
    }


    @Override
    public Integer add(SelectProblemUploadDto selectProblemParam) {
        List<TagVo> tags = selectProblemParam.getTags();
        SelectProblem selectProblem = selectProblemMapper.uploadDtoToDo(selectProblemParam);
        if (selectProblemRepository.insert(selectProblem) > 0){
            doProblemRelatedTag(tags,selectProblem);
            //tags.forEach(tagBo -> tagService.addTag(tagBo.getName()));
            return selectProblem.getId();
        }else {
            throw new ResourceNotFoundException(String.format("新增题目失败"));
        }
        //selectProblemRepository.insert(selectProblem);
    }

    @Override
    public boolean delete(Integer problemId) {
        return (problemTagRepository.deleteByProblemId(problemId,null) > 0 && selectProblemRepository.deleteById(problemId) > 0) ? true : false;
    }


    private  List InitListOfAllProblems(){
        List<SelectProblemParam> selectProblems = getSelectProblem();
        List listAll = new ArrayList();
        for (SelectProblemParam selectProblem:selectProblems){
            listAll.add(selectProblem);
        }
        return listAll;
    }

    @Override
    public List<TagVo> findTagBySelectProblemId(Integer id) {
        List<Tag> res = problemTagRepository.findTagBySelectProblemId(id);
        if (res == null) {
            return Collections.emptyList();
        }
        return tagMapper.doToVo(res);
    }


    public static List<Answer> conversion(String str){
        List<Answer> answers = JSON.parseArray(str, Answer.class);
        return answers;
    }

    /**
     * 将标签和问题进行一个关联
     */
    private void doProblemRelatedTag(List<TagVo> tags, SelectProblem problemDo) {
        if (ObjectUtils.isEmpty(tags)) {
            return;
        }
        List<ProblemTag> problemTags = new ArrayList<>();
        for (TagVo tag : tags) {
            Tag addTag = tagService.addTag(tag.getName());
            TagVo tagVo = tagMapper.doToVo(addTag);
            ProblemTag problemTag = new ProblemTag();
            problemTag.setProblemId(problemDo.getId());
            problemTag.setTagId(tagVo.getId());
            problemTag.setType(problemDo.getType());
            problemTags.add(problemTag);
        }
        problemTagRepository.insertAll(problemTags);
    }

    @Override
    public  List<SelectProblemParam> sorter(IPage<SelectProblem> selectProblemIPage,Integer pageNum){
        if(selectProblemIPage.getRecords().size() != 0 ){
            List<SelectProblemParam> records = new ArrayList<>();
            if (!CollectionUtils.isEmpty(selectProblemIPage.getRecords())){
                records = (List<SelectProblemParam>) selectProblemIPage.getRecords().stream().map(selectProblem -> {
                    SelectProblemBo bo = selectProblemMapper.to(selectProblem);
                    SelectProblemParam selectProblemParam = new SelectProblemParam(
                            bo.getId(),
                            bo.getType(),
                            bo.getTitle(),
                            bo.getAnswer(),
                            bo.getCorrect(),
                            bo.getLevel(),
                            tagMapper.doToVo(problemTagRepository.findTagBySelectProblemId(bo.getId())),
                            bo.getUserId(),
                            bo.getIndexId()
                    );
                    return selectProblemParam;
                }).collect(Collectors.toList());;
            }
            return records;
        }else {
            throw new ResourceNotFoundException(String.format("当前页不存在"));
        }

    }

    @Override
    public List<SelectProblemParam> searchProblems(String tag, String title, Integer type, Integer pageNum, Integer pageSize) {
        IPage<SelectProblem> page = new Page<>(pageNum, pageSize);
        IPage<SelectProblem> selectProblemIPage = selectProblemRepository.searchProblem(page,tag,title,type);
        List<SelectProblemParam> selectProblems = sorter(selectProblemIPage, pageNum);
        return selectProblems;
    }

    @Override
    public List<SelectProblemParam> searchByTagAndTitle(String tag, String title) {
        List<SelectProblem> selectProblems = selectProblemRepository.searchByTagAndTitle(tag,title);
        List<SelectProblemBo> bos = selectProblemMapper.to(selectProblems);
        List<SelectProblemParam> params = new ArrayList<>();
        for (SelectProblemBo bo:bos){
            SelectProblemParam selectProblemParam = new SelectProblemParam(
                    bo.getId(),
                    bo.getType(),
                    bo.getTitle(),
                    bo.getAnswer(),
                    bo.getCorrect(),
                    bo.getLevel(),
                    tagMapper.doToVo(problemTagRepository.findTagBySelectProblemId(bo.getId())),
                    bo.getUserId(),
                    bo.getIndexId()
            );
            params.add(selectProblemParam);
        }
        return params;
    }

    @Override
    public boolean updateTestCaseIdById(Integer problemId,String testCaseId){
        return selectProblemRepository.updateTestCaseIdById(problemId, testCaseId) > 0;

    }

    @Override
    public String getTestCaseIdById(Integer problemId){
        return selectProblemRepository.getTestCaseIdById(problemId);
    }



}
